package com.hss.thread;
/*
* https://www.cnblogs.com/huajiezh/p/5868681.html
1.sleep()方法

在指定时间内让当前正在执行的线程暂停执行，但不会释放“锁标志”。不推荐使用。

sleep()使当前线程进入阻塞状态，在指定时间内不会执行。

2.wait()方法

在其他线程调用对象的notify或notifyAll方法前，导致当前线程等待。线程会释放掉它所占有的“锁标志”，从而使别的线程有机会抢占该锁。

当前线程必须拥有当前对象锁。如果当前线程不是此锁的拥有者，会抛出IllegalMonitorStateException异常。

唤醒当前对象锁的等待线程使用notify或notifyAll方法，也必须拥有相同的对象锁，否则也会抛出IllegalMonitorStateException异常。

waite()和notify()必须在synchronized函数或synchronized　block中进行调用。如果在non-synchronized函数或non-synchronized　block中进行调用，虽然能编译通过，但在运行时会发生IllegalMonitorStateException的异常。

3.yield方法

暂停当前正在执行的线程对象。

yield()只是使当前线程重新回到可执行状态，所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。

yield()只能使同优先级或更高优先级的线程有执行的机会。

yield()应该做的是让当前运行线程回到可运行状态，以允许具有相同优先级的其他线程获得运行机会。因此，使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是，实际中无法保证yield()达到让步目的，因为让步的线程还有可能被线程调度程序再次选中。

4.join方法

等待该线程终止。

等待调用join方法的线程结束，再继续执行。如：t.join();//主要用于等待t线程运行结束，若无此句，main则会执行完毕，导致结果不可预测。

二、run和start()

把需要处理的代码放到run()方法中，start()方法启动线程将自动调用run()方法，这个由java的内存机制规定的。并且run()方法必需是public访问权限，返回值类型为void。


 三、关键字synchronized

该关键字用于保护共享数据，当然前提条件是要分清哪些数据是共享数据。每个对象都有一个锁标志，当一个线程访问到该对象，被Synchronized修饰的数据将被"上锁"，阻止其他线程访问。当前线程访问完这部分数据后释放锁标志，其他线程就可以访问了。

四、wait()和notify(),notifyAll()是Object类的方法，sleep()和yield()是Thread类的方法。


(1)、常用的wait方法有wait()和wait(long timeout);

void wait() 在其他线程调用此对象的 notify() 方法或者 notifyAll()方法前，导致当前线程等待。

void wait(long timeout)在其他线程调用此对象的notify() 方法 或者 notifyAll()方法，或者超过指定的时间量前，导致当前线程等待。

wait()后，线程会释放掉它所占有的“锁标志”，从而使线程所在对象中的其他shnchronized数据可被别的线程使用。

wait()h和notify()因为会对对象的“锁标志”进行操作，所以他们必需在Synchronized函数或者 synchronized block 中进行调用。如果在non-synchronized 函数或 non-synchronized block 中进行调用，虽然能编译通过，但在运行时会发生IllegalMonitorStateException的异常。。

(2)、Thread.sleep(long millis)必须带有一个时间参数。

sleep(long)使当前线程进入停滞状态，所以执行sleep()的线程在指定的时间内肯定不会被执行；

sleep(long)可使优先级低的线程得到执行的机会，当然也可以让同优先级的线程有执行的机会；

sleep(long)是不会释放锁标志的。

(3)、yield()没有参数

sleep 方法使当前运行中的线程睡眠一段时间，进入不可以运行状态，这段时间的长短是由程序设定的，yield方法使当前线程让出CPU占有权，但让出的时间是不可设定的。

yield()也不会释放锁标志。

实际上，yield()方法对应了如下操作；先检测当前是否有相同优先级的线程处于同可运行状态，如有，则把CPU的占有权交给次线程，否则继续运行原来的线程，所以yield()方法称为“退让”，它把运行机会让给了同等级的其他线程。

sleep 方法允许较低优先级的线程获得运行机会，但yield（）方法执行时，当前线程仍处在可运行状态，所以不可能让出较低优先级的线程此时获取CPU占有权。在一个运行系统中，如果较高优先级的线程没有调用sleep方法，也没有受到I/O阻塞，那么较低优先级线程只能等待所有较高优先级的线程运行结束，方可有机会运行。

yield()只是使当前线程重新回到可执行状态，所有执行yield()的线程有可能在进入到可执行状态后马上又被执行，所以yield()方法只能使同优先级的线程有执行的机会。

*
*
*
* */
public class ThreadTest {
    public static void main(String[] args) {
//        joinTest();

//        waitTest();

        yieldTest();
    }

    //******************************** join ***************************************
    static void joinTest(){
        Thread t1 = new MyThread1();
        t1.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("主线程第" + i +"次执行！");
            if (i > 1)try {
                //t1线程合并到主线程中，主线程停止执行过程，转而执行t1线程，直到t1执行完毕后继续。
                t1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class MyThread1 extends Thread {
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("线程1第" + i + "次执行！");
            }
        }
    }

    //**********************************  join   *************************************



    //**********************************  wait  *************************************

    static void waitTest(){
        ThreadA t1 = new ThreadA("t1");
        synchronized(t1) {
            try {
                // 启动“线程t1”
                System.out.println(Thread.currentThread().getName()+" start t1");
                t1.start();
                // 主线程等待t1通过notify()唤醒。
                System.out.println(Thread.currentThread().getName()+" wait()");
                t1.wait();  //  不是使t1线程等待，而是当前执行wait的线程等待
                System.out.println(Thread.currentThread().getName()+" continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    static class ThreadA extends Thread{
        public ThreadA(String name) {
            super(name);
        }

        @Override
        public void run() {
            super.run();
            synchronized (this){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" call notify()");
                // 唤醒当前的wait线程
                this.notify();
            }
        }
    }


    //**********************************  yeild  *************************************

    static void yieldTest(){
        Thread t1 = new Thread(new YeildRunable("t1"));
        Thread t2 = new Thread(new YeildRunable("t2"));
        t1.start();
        t2.start();
    }

    static class YeildRunable implements Runnable{

        String name;

        public YeildRunable(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            for (int i=0;i <100 ;i++){
                if (i>0 &&i%5 ==0){
                    System.out.println(name  + ":" + i +"......yield.............");
                    Thread.yield();
                }

            }
        }
    }
}
